home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
pascal
/
cpuidjl.exe
/
CPUID.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-07-14
|
6KB
|
226 lines
{
Here is some code that identifies the CPU and FPU of your computer. It
demonstrates coordination of INLINE, ASM and standard Pascal code. This
routine uses INTEL recommended CPU identification techniques. It also
demontrates two techniques that may be used to address the extended
registers of the 386 and 486.
Donated to the public domain. John D. Leonard II
}
unit cpuid;
interface
Procedure CPUFPUID(var CPU,FPU:integer);
{- This routine determine the type of CPU and FPU (Floating Point Unit)
using INTEL recommended techniques as posted in CPUID.ASM on the
PCEO Intel Forum. It has been supplemented with a check for the
386SX }
{-Returns 1: 8088/8086
2: 80286
3: 80386 -3: 80386SX
4: 80486 -}
{-This routine does not require external OBJ files, all assembler
calls are implemented using ASM directive or INLINE code. -}
{-Use of INLINE was required, as the TP6 ASM processor does not
recognize 386/486 specific register addressing -}
{-The procedure first determines the CPU type by filtering through
a series of tests. Then, the FPU check is performed. -}
{-This procedure demonstrates the use of ASM directives and INLINE
code, in conjunction with regular TP assignments and labels. -}
{-This code as been tested with 8088, 80286, 80386, 80386sx and 80486,
(Yes, Virginia, we have them all sitting around the place.) }
{ ==================================================================== }
implementation
Procedure CPUFPUID(var CPU,FPU:integer);
label check_fpu,stop,restore_eflags;
var fp_status:word;
begin
{- Begin a series of tests to determine CPU type ... -}
{- On an 8086/8088 Flag Bits 12-15 are always set -}
cpu := 1;
asm
PUSHF
POP BX
MOV AX,0FFFH
AND AX,BX
PUSH AX
POPF
PUSHF
POP AX
AND AX,0F000H
CMP AX,0F000H
JE CHECK_FPU
end;
{- On a 80286 Flag Bits 12-15 are always clear -}
cpu := 2;
asm
OR BX,0F000H
PUSH BX
POPF
PUSHF
POP AX
AND AX,0F000H
JZ CHECK_FPU
end;
{- On a 80486, bit 18 of EFLAGS can be set. It can't be set on 386.
(This bit relates to generation of alignment faults. )
Note the use of DB 66H in this code for reference to the
386 extended registers. It acts like a SHIFT key, allowing direct
translation of some addressing commands between the standard
registers and the 386/486 extended registers. }
cpu := 4;
asm
{- Align Stack to prevent a fault -}
MOV DX,SP { MOV DX, SP }
AND SP, NOT 3 { AND SP, NOT 3 }
{- Get EFLAGS and store in ECX for later comparison and restoration }
DB 66H
PUSHF { PUSHFD }
DB 66H
POP AX { POP EAX }
DB 66H
MOV CX,AX { MOV ECX,EAX }
{- Set Bit #18. Note use of DW to get large integer -}
DB 66H
XOR AX,0
DW 4H { XOR EAX,40000H }
{- Stick the result into EFLAGS, and get it back. Keep in EAX -}
DB 66H
PUSH AX { PUSH EAX }
DB 66H
POPF { POPFD }
DB 66H
PUSHF { PUSHFD }
DB 66H
POP AX { POP EAX }
{- Restore Flags and Stack before making comparison -}
DB 66H
PUSH CX { PUSH ECX }
DB 66H
POPF { POPFD }
MOV SP,DX { MOV SP,DX }
DB 66H
XOR AX,CX { XOR EAX,ECX }
JNZ CHECK_FPU
end;
{- On a 386, the coprocessor type bit in CR0 can be set. On a 386Sx,
it can not be set. NOTE: this test is not a part of the recommended
INTEL CPU check code. ALSO NOTE: this code can not determine early
versions of the 386sx, as they allow this bit to be set. INLINE was
required, as there is no way to "shift" ala "DB 66H" to access CR0. }
cpu := -3;
inline( $0f/$20/$c0 ); { MOV EAX,CR0 }
inline( $66/$8b/$c8 ); { MOV ECX,EAX }
inline( $66/$83/$F0/$10); { MOV EAX,10H }
inline( $0f/$22/$c0 ); { MOV CR0,EAX }
inline( $0f/$20/$c0 ); { MOV EAX,CR0 }
inline( $0f/$22/$c1 ); { MOV CR0,ECX }
inline( $66/$33/$c1 ); { XOR EAX,ECX }
asm
JZ CHECK_FPU
end;
{- The default CPU type, if all else fails. -}
cpu := 3;
{- Begin CoProcessor Check. We first check if the FPU can be initialized.
If not, there is no FPU. If we have got one, it will, in general
match the CPU type, i.e. 8087 goes with 8086/88, 287 goes with 286, etc.
The only exception is the 386, which may use either the 387 or 287. }
CHECK_FPU:
{- Can we initialize the CoProcessor? -}
FPU := 0;
asm
FNINIT
MOV FP_STATUS,5A5AH
FNSTSW FP_STATUS
MOV AX,FP_STATUS
JNE STOP
FNSTCW FP_STATUS
MOV AX,FP_STATUS
AND AX,103FH
CMP AX,3FH
JNE STOP
end;
{- Yes! Assign the corresponding FPU based on CPU -}
FPU := abs(CPU);
{- However, if we have a 386/386SX, we must determine 387 or 287. A 387
differentiates between positive and negative infinity, a 287 does not. }
if FPU=3 then begin
FPU := 2;
asm
FLD1
FLDZ
FDIV
FLD ST
FCHS
FCOMPP
FSTSW FP_STATUS
MOV AX,FP_STATUS
SAHF
JZ STOP
end;
fpu := 3;
end;
stop:
end;
end.